package com.nikmesoft.nmsharekit.helpers;

import java.util.Arrays;
import java.util.List;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;
import com.facebook.FacebookAuthorizationException;
import com.facebook.FacebookOperationCanceledException;
import com.facebook.FacebookRequestError;
import com.facebook.HttpMethod;
import com.facebook.LoggingBehavior;
import com.facebook.Request;
import com.facebook.RequestAsyncTask;
import com.facebook.Response;
import com.facebook.Session;
import com.facebook.SessionState;
import com.facebook.Settings;
import com.facebook.model.GraphUser;
import com.nikmesoft.nmsharekit.R;
import com.nikmesoft.nmsharekit.delegates.NMSKFacebookDialogDelegate;
import com.nikmesoft.nmsharekit.objects.NMShareMessage;
import com.nikmesoft.nmsharekit.objects.NMShareMessage.NMShareType;
import com.nikmesoft.nmsharekit.utils.NMSKFacebookSession;
import com.nikmesoft.nmsharekit.views.NMSKFacebookDialog;

public class NMSKFacebookHelper implements NMSKFacebookDialogDelegate {
	public static NMSKFacebookHelper instance;

	private static final List<String> PERMISSIONS = Arrays
			.asList("publish_actions");

	private static final String TAG = NMSKFacebookHelper.class.getSimpleName();

	private PendingAction pendingAction = PendingAction.NONE;

	private NMShareMessage message;

	private enum PendingAction {
		NONE, GET_USER_INFO, POST
	}

	private Activity activity;
	private Context context;

	// share instance
	public static NMSKFacebookHelper sharedInstance(Context context,
			Activity activity) {
		if (instance == null) {
			instance = new NMSKFacebookHelper(context, activity);
		}
		return instance;
	}

	public NMSKFacebookHelper(Context context, Activity activity) {
		super();
		this.activity = activity;
		this.context = context;
		Settings.addLoggingBehavior(LoggingBehavior.INCLUDE_ACCESS_TOKENS);
	}

	// share a new status via facebook
	public void share(NMShareMessage message) {
		this.message = message;
		Session session = Session.getActiveSession();
		if (session != null && session.isOpened()) {
			performPublish(PendingAction.GET_USER_INFO);
		} else if (session == null) {
			pendingAction = PendingAction.GET_USER_INFO;
			session = new Session.Builder(context).build();
			session.addCallback(callback);
			Session.OpenRequest openRequest = new Session.OpenRequest(activity);
			openRequest.setRequestCode(Session.DEFAULT_AUTHORIZE_ACTIVITY_CODE);
			openRequest.setPermissions(PERMISSIONS);
			session.openForPublish(openRequest);
			Session.setActiveSession(session);
		} else {

			pendingAction = PendingAction.GET_USER_INFO;
			Session.openActiveSession(activity, true, callback);
		}
	}

	// section callback
	private Session.StatusCallback callback = new Session.StatusCallback() {
		@Override
		public void call(Session session, SessionState state,
				Exception exception) {
			onSessionStateChange(session, state, exception);
		}
	};

	// process when session state changed
	private void onSessionStateChange(Session session, SessionState state,
			Exception exception) {
		Log.i(TAG, state.name());
		if (exception instanceof FacebookOperationCanceledException
				|| exception instanceof FacebookAuthorizationException) {
			pendingAction = PendingAction.NONE;
		} else if (state == SessionState.OPENED
				|| state == SessionState.OPENED_TOKEN_UPDATED) {
			handlePendingAction();
		}
	}

	// handle action
	private void handlePendingAction() {
		PendingAction previouslyPendingAction = pendingAction;
		Log.i(TAG, previouslyPendingAction.toString());
		pendingAction = PendingAction.NONE;
		switch (previouslyPendingAction) {
		case POST:
			callWS();
			break;
		case GET_USER_INFO:
			fetchUserInfo();
			break;
		default:
			break;
		}
	}

	// check publish permission
	private boolean hasPublishPermission() {
		Session session = Session.getActiveSession();
		return session != null
				&& session.getPermissions().contains("publish_actions");
	}

	private void callWS() {
		Session session = Session.getActiveSession();
		if (session != null) {
			if (hasPublishPermission()) {
				Bundle postParams = new Bundle();
				postParams.putString("message", message.getMessage());
				if (message.getType() == NMShareType.NMShareTypeStory) {
					postParams.putString("name", message.getName());
					postParams.putString("caption", message.getCaption());
					postParams.putString("description",
							message.getDescription());
					postParams.putString("link", message.getLink());
					postParams.putString("picture", message.getPicture());
				}
				Request.Callback callback = new Request.Callback() {
					public void onCompleted(Response response) {
						FacebookRequestError error = response.getError();
						if (error != null) {
							Toast.makeText(activity.getApplicationContext(),
									error.getErrorMessage(), Toast.LENGTH_SHORT)
									.show();
						} else {
							Toast.makeText(activity.getApplicationContext(),
									activity.getString(R.string.fb_posted),
									Toast.LENGTH_LONG).show();
						}
					}
				};

				Request request = new Request(session, "me/feed", postParams,
						HttpMethod.POST, callback);

				RequestAsyncTask task = new RequestAsyncTask(request);
				task.execute();

			} else {
				pendingAction = PendingAction.POST;
			}
		}
	}

	// get user info
	private void fetchUserInfo() {
		final Session currentSession = Session.getActiveSession();
		if (currentSession != null && currentSession.isOpened()) {
			Request request = Request.newMeRequest(currentSession,
					new Request.GraphUserCallback() {
						@Override
						public void onCompleted(GraphUser me, Response response) {
							if (response.getRequest().getSession() == currentSession) {
								NMSKFacebookSession.getInstance(context)
										.storeUsername(me.getName());
								// show share dialog
								NMSKFacebookDialog.show(context, activity,
										NMSKFacebookHelper.this, message);
							}
						}

					});
			request.executeAsync();
		}
	}

	private void performPublish(PendingAction action) {
		Session session = Session.getActiveSession();
		if (session != null) {
			pendingAction = action;
			if (hasPublishPermission()) {
				// We can do the action right away.
				handlePendingAction();
			} else {
				// We need to get new permissions, then complete the action when
				// we get called back.
				session.requestNewPublishPermissions(new Session.NewPermissionsRequest(
						activity, PERMISSIONS));
			}
		}
	}

	// NMSKFacebookDialogDelegate
	@Override
	public void cancel() {

	}

	@Override
	public void didSharedWithMessage(NMShareMessage message) {
		this.message = message;
		performPublish(PendingAction.POST);
	}

}
